package com.tsd.core.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 字符串及字符串数组的工具类，包括在字符串数组中查找值(元素)、数组合并、判断是否有交集、等。
 * 此类依赖jakarta-oro-2.0.8.jar、commons-logging.jar
 *
 * @author sujo
 */
public class StringUtil {

    private final static Log log = LogFactory.getLog(StringUtil.class);

    /**
     * 判断字符串是否为空，如为空，返回空字符串""，否则返回原字符串
     *
     * @param value
     * @return
     */
    public static String getNotNullString(String value) {
        String ret = "";
        if (null != value)
            ret = value;
        return ret;
    }

    /**
     * 判断字符串是否为空
     * null，非空字符串去掉了前后空格的值为："","null"也被认为是空字符串
     *
     * @param str
     * @return
     */
    public static boolean isEmpty(String str) {
        return (str == null || "".equals(str.trim()) || "null".equalsIgnoreCase(str.trim()));
    }

    /**
     * 将字节数组转换成16进制字符串
     *
     * @param b 字节数组
     */
    public static String byteToHexString(byte[] b) {
        String strResutl = "";
        if (null == b)
            return null;
        for (int i = 0; i < b.length; i++) {
            strResutl += Integer
                    .toHexString((0x000000ff & b[i]) | 0xffffff00)
                    .substring(6);

        }
        return strResutl;
    }

    /**
     * 转义HTML标签和特殊字符，令其在html浏览器中可以显示出来<br>
     * 输入：ab&lt;d&#39ked\&quot;kiesf&amp;amp;skd&gt;ek\nddddsdfe&nbsp;sdsf，<br>
     * 输出：ab&amp;lt;d&amp;#39ked&amp;quot;kiesf&amp;amp;skd&amp;gt;ek&lt;br&gt;ddddsdfe&amp;nbsp;sdsf
     *
     * @param str 输入的html脚本
     * @return 转义后的字符串
     */
    public static String escapeHTML(String str) {

        if (str != null) {
//		      str = str.replaceAll("&", "&amp");
//		      str = str.replaceAll("<", "&lt");
//		      str = str.replaceAll(">", "&gt");
//		      str = str.replaceAll("\"", "&quot");
            str = str.replaceAll("'", "&#39");
            str = str.replaceAll("\n", "<br>");
            str = str.replaceAll(" ", "&nbsp;");
        }
//		    return str;
        //经查资料对照，转义对应算法正确  --hesz 2010.12.13
        if (str == null) {
            return null;
        }

        char[] s = str.toCharArray();
        int length = s.length;
        StringBuffer ret = new StringBuffer(length + 100);// add more room to the result String

        for (int i = 0; i < length; i++) {
            //增加对换行的处理
            if (s[i] == '<' && s[i + 1] == 'b' && s[i + 2] == 'r' && s[i + 3] == '>') {
                ret.append("<br>");
                i += 3;
            } else if (s[i] == '<') {
                ret.append("&lt;");
            } else if (s[i] == '>') {
                ret.append("&gt;");
            } else if (s[i] == '&') {
                // this hack the escape for unicode character, eg : &2345;
                if (((i + 3) < length) &&
                        (s[i + 1] == '#') &&
                        (s[i + 2] >= '0' && s[i + 2] <= '9') &&
                        (s[i + 3] >= '0' && s[i + 3] <= '9')) {
                    ret.append(s[i]);
                    // hack &lt; (dont escape this char more than once)
                } else if (((i + 3) < length) &&
                        (s[i + 1] == 'l') &&
                        (s[i + 2] == 't') &&
                        (s[i + 3] == ';')) {
                    ret.append(s[i]);
                    // hack &gt; (dont escape this char more than once)
                } else if (((i + 3) < length) &&
                        (s[i + 1] == 'g') &&
                        (s[i + 2] == 't') &&
                        (s[i + 3] == ';')) {
                    ret.append(s[i]);
                    // hack &amp; (dont escape this char more than once)
                } else if (((i + 4) < length) &&
                        (s[i + 1] == 'a') &&
                        (s[i + 2] == 'm') &&
                        (s[i + 3] == 'p') &&
                        (s[i + 4] == ';')) {
                    ret.append(s[i]);
                    // hack &quot; (dont escape this char more than once)
                } else if (((i + 5) < length) &&
                        (s[i + 1] == 'q') &&
                        (s[i + 2] == 'u') &&
                        (s[i + 3] == 'o') &&
                        (s[i + 4] == 't') &&
                        (s[i + 5] == ';')) {
                    ret.append(s[i]);
                } else if (((i + 5) < length) &&
                        (s[i + 1] == 'n') &&
                        (s[i + 2] == 'b') &&
                        (s[i + 3] == 's') &&
                        (s[i + 4] == 'p') &&
                        (s[i + 5] == ';')) {//增加对空格的处理
                    ret.append(s[i]);
                } else {
                    ret.append("&amp;");
                }
            } else if (s[i] == '"') {
                ret.append("&quot;");
            } else {
                ret.append(s[i]);
            }
        }// for
        return ret.toString();
    }

    public static String htmlTruncateString(String source, int width) {
        return strCtrl(escapeHTML(source), (width - 10) / 7);
    }

    /**
     * 转换str，浏览器界面输出，长度限制在len内.
     *
     * @param str 原始字符串.
     * @param len 输出长度的限制.
     * @returnStr 经过转换的字符串.
     */
    public static String strCtrl(String str, int len) {
        String returnStr = "";
        if (str == null || str.trim().length() == 0) {
            return returnStr;
        }
        //str = escapeHTML(str);
        char[] temp1 = new char[1];
        temp1[0] = (char) 10;  //处理回车和换行符
        char[] temp2 = new char[1];
        temp2[0] = (char) 13;
        str = str.replaceAll(new String(temp1), " ");
        str = str.replaceAll(new String(temp2), " ");

        int length = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.indexOf("&nbsp;", i) == i) { // 空格
                length += 1;
                if (length > len)
                    break;
                returnStr += "&nbsp;";
                i += 5;
            } else if (str.indexOf("&#39;", i) == i) { // '
                length += 1;
                if (length > len)
                    break;
                returnStr += "&#39;";
                i += 4;
            } else if (str.indexOf("&amp;", i) == i) { // &
                length += 1;
                if (length > len)
                    break;
                returnStr += "&amp;";
                i += 4;
            } else if (str.indexOf("&lt;", i) == i) { // <
                length += 1;
                if (length > len)
                    break;
                returnStr += "&lt;";
                i += 3;
            } else if (str.indexOf("&gt;", i) == i) { // >
                length += 1;
                if (length > len)
                    break;
                returnStr += "&gt;";
                i += 3;
            } else if (str.indexOf("&quot;", i) == i) { // "
                length += 1;
                if (length > len)
                    break;
                returnStr += "&quot;";
                i += 5;
            } else {
                if (str.charAt(i) > 255)   //汉字
                    length += 2;
                else
                    length += 1;
                if (length > len)
                    break;
                returnStr += str.charAt(i);
            }
        }
        if (length > len)
            returnStr += "...";

        return returnStr;
    }

    /**
     * 根据a=a1;b=b1;...格式字符串返回map，a、b为键，a1、b1为值，等效于map.put("a","a1");map.put("b","b1");
     *
     * @param src 原字符串
     * @return Map对象
     */
    public static Map getMapFromString(String src) {
        if (src == null || src.trim().length() == 0) {
            return null;
        }
        String[] doc = src.split(";");
        HashMap map = null;
        if (doc != null) {
            int ilen = doc.length;
            String[] equal = null;
            map = new HashMap();
            for (int i = 0; i < ilen; i++) {
                equal = doc[i].split("=");
                if (equal != null && equal.length > 1) {
                    map.put(equal[0], equal[1]);
                }
            }
        }
        return map;
    }

    /**
     * 把String类型转为其他类型
     *
     * @param s       原字符串
     * @param toClass 转到的对象类
     * @return 转换后的对象
     */
    public static Object convert(String s, Class toClass) {
        Object entity = s;

        if (null == toClass || null == s || "".equals(s.trim())) {
            return entity;
        }

        if ("int".equals(toClass.getSimpleName()) || "Integer".equals(toClass.getSimpleName())) {
            entity = Integer.valueOf(s);
        }
        if ("float".equals(toClass.getSimpleName()) || "Float".equals(toClass.getSimpleName())) {
            entity = Float.valueOf(s);
        }
        if ("double".equals(toClass.getSimpleName()) || "Double".equals(toClass.getSimpleName())) {
            entity = Double.valueOf(s);
        }
        if ("boolean".equals(toClass.getSimpleName()) || "Boolean".equals(toClass.getSimpleName())) {
            entity = Boolean.valueOf(s);
        }
        if ("long".equals(toClass.getSimpleName()) || "Long".equals(toClass.getSimpleName())) {
            entity = Long.valueOf(s);
        }

        return entity;
    }

    /**
     * 字符串str中是否包含项subStr，各项之间用,号隔开
     *
     * @param str    原字符串
     * @param subStr 子字符串
     * @return 是否包含
     * @author fangjp 2009.08.03
     */
    public static boolean contains(String str, String subStr, String splitStr) {
        //判断参数的合法性
        if (null == str || null == subStr || null == splitStr)
            return false;
        return (splitStr + str + splitStr).indexOf(splitStr + subStr + splitStr) > -1;
    }

    /**
     * 合并两个字符串的项，各项之间用指定分隔符隔开
     *
     * @param s1
     * @param s2
     * @param splitStr 指定分隔符
     * @return
     */
    public static String mergeString(String s1, String s2, String splitStr) {
        if (s1 == null || s1.length() == 0)
            return s2;
        if (s2 == null || s2.length() == 0)
            return s1;
        String[] array2 = s2.split(splitStr);
        for (int i = 0; i < array2.length; i++) {
            if (!contains(s1, array2[i], splitStr))
                s1 += splitStr + array2[i];
        }
        return s1;
    }

    /**
     * 为字符串的每个项添加单引号，各项之间用","号隔开
     * added by fangjp 2009-7-23
     */
    public static String addSingleQuotesAndSpitByComma(String str) {
        String result = "";
        if (str == null || str == "")
            return result;
        else {
            return "'" + str.replaceAll(",", "','") + "'";
        }
    }

    /**
     * 首字母大写
     *
     * @param str 原字符串
     * @return 首字母转为大写后的字符串
     */
    public static String firstUpperCase(String str) {
        if (str == null || str.length() == 0) return str;
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 首字母小写
     *
     * @param str 原字符串
     * @return 首字母转为小写后的字符串
     */
    public static String firstLowerCase(String str) {
        if (str == null || str.length() == 0) return str;
        return str.substring(0, 1).toLowerCase() + str.substring(1);
    }

    /**
     * 转义引号、斜杠\、反斜杠/、换行\r、回车\n、退格\b、\f、Tab键输入\t及其他控制符(U+0000 through U+001F).
     *
     * @param s 输入的字符串
     * @return 转义后的字符串
     */
    public static String escape_123(String s) {
        if (s == null)
            return null;
        StringBuffer sb = new StringBuffer();
        escape_123(s, sb);
        return sb.toString();
    }

    /**
     * 转义特殊字符
     *
     * @param s  - Must not be null.
     * @param sb
     */
    static void escape_123(String s, StringBuffer sb) {
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            switch (ch) {
                case '"':
                    sb.append("\\\"");
                    break;
                case '\\':
                    sb.append("\\\\");
                    break;
                case '\b':
                    sb.append("\\b");
                    break;
                case '\f':
                    sb.append("\\f");
                    break;
                case '\n':
                    sb.append("\\n");
                    break;
                case '\r':
                    sb.append("\\r");
                    break;
                case '\t':
                    sb.append("\\t");
                    break;
                case '/':
                    sb.append("\\/");
                    break;
                default:
                    //Reference: http://www.unicode.org/versions/Unicode5.1.0/
                    if ((ch >= '\u0000' && ch <= '\u001F')
                            || (ch >= '\u007F' && ch <= '\u009F')
                            || (ch >= '\u2000' && ch <= '\u20FF')) {
                        String ss = Integer.toHexString(ch);
                        sb.append("\\u");
                        for (int k = 0; k < 4 - ss.length(); k++) {
                            sb.append('0');
                        }
                        sb.append(ss.toUpperCase());
                    } else {
                        sb.append(ch);
                    }
            }
        }//for
    }

    /**
     * 格式化linux关机时间参数
     *
     * @param hour 小时
     * @param min  分钟
     * @return
     */
    public static String parseCronParam(String hour, String min) {
        if (hour == null || "".equals(hour))
            return "0 0 2 * * ?"; //默认值


        String cronParam = "0 " +
                min +
                " " +
                hour +
                " * * ?";
        return cronParam;
    }

    /**
     * 在String数组arr的指定区间查找值为value的元素
     *
     * @param arr        源String数组
     * @param value      要查找的元素字符(关键字)
     * @param m          查找起始位置
     * @param n          查找结束位置
     * @param caseIgnore 是否忽略大小写
     * @return 返回找到的数组索引位置
     */
    public static int indexOf(String[] arr, String value, int m, int n, boolean caseIgnore) {
        if (value == null) {
            log.error("入参value为空");
            return -1;
        }
        if (arr == null) {
            log.error("入参arr为空");
            return -1;
        } else if (arr.length <= m) {
            return -1;
        } else if (m > n) {
            return -1;
        } else {
            for (int i = m; i <= n; i++) {
                if (caseIgnore) {
                    if (i < arr.length && value.equalsIgnoreCase(arr[i])) {
                        return i;
                    }
                } else if (value.equals(arr[i])) {
                    return i;
                }

            }

        }
        return -1;
    }

    /**
     * 在String数组arr中查找值为value的元素，忽略大小写
     *
     * @param arr   源String数组
     * @param value 要查找的元素字符(关键字)
     * @return 返回找到的数组索引位置
     */
    public static int indexOf(String[] arr, String value) {
        return indexOf(arr, value, true);
    }

    /**
     * 在String数组arr中查找值为value的元素
     *
     * @param arr        源String数组
     * @param value      要查找的元素字符(关键字)
     * @param caseIgnore 是否忽略大小写
     * @return 返回找到的数组索引位置
     */
    public static int indexOf(String[] arr, String value, boolean caseIgnore) {
        return indexOf(arr, value, 0, arr.length, caseIgnore);
    }

    /**
     * 合并两个String数组arr1、arr2，得到一个没有重复元素的String
     *
     * @param arr1     String数组1
     * @param arr2     String数组1
     * @param splitStr 分隔符
     * @return 以splitStr分割的String
     */
    public static String merge(String[] arr1, String[] arr2, String splitStr) {
        String str = "";
        if (arr1 != null && arr1.length > 0) {
            for (int i = 0; i < arr1.length; i++) {
                if (i == 0) str = arr1[i];
                else {
                    if (arr1[i] != null)
                        str = str + splitStr + arr1[i];
                }
            }
            for (int i = 0; i < arr2.length; i++) {
                if (arr2[i] != null && indexOf(arr1, arr2[i]) < 0) {
                    if (str == null) {
                        str = arr2[i];
                    } else {
                        str = str + splitStr + arr2[i];
                    }
                }
            }

        } else if (arr2 != null && arr2.length > 0) {
            for (int i = 0; i < arr2.length; i++) {
                if (i == 0 && arr2[i] != null) str = arr2[i];
                else if (arr2[i] != null) {
                    if (str != null) {
                        str = arr2[i];
                    } else {
                        str = str + splitStr + arr2[i];
                    }

                }
            }
        }
        return str;
    }

    /**
     * 合并两个String，去掉以splitStr分隔开的字符串重复
     * 如 str1="zz,hua,rock" str2="zz,hua,other" splitStr=","
     * 则合并后的string为"zz,hua,rock,other"
     * 此方法不考虑次序的问题
     *
     * @param str1     源数组1
     * @param str2     源数组1
     * @param splitStr 分隔符
     * @return 以splitStr分隔的不重复字符串
     */
    public static String merge(String str1, String str2, String splitStr) {
        if (str1 == null) {
            return str2;
        }
        if (str2 == null) {
            return str1;
        }
        if (splitStr != null) {
            String[] arr1 = str1.split(splitStr);
            String[] arr2 = str2.split(splitStr);
            return merge(arr1, arr2, splitStr);
        } else if (str1.equals(str2))
            return str1;
        else
            return str1 + str2;
    }

    /**
     * 把数组转换为String，以逗号(",")分割各元素
     *
     * @param objs 源数组
     * @return 以逗号分割的String
     */
    public static String Array2String(Object[] objs) {
        return Array2String(objs, ",");
    }

    /**
     * 把数组转换为String，以指定分隔符splitStr分割各元素
     *
     * @param objs     源数组
     * @param splitStr 分隔符
     * @return 以splitStr分割的String
     */
    public static String Array2String(Object[] objs, String splitStr) {
        String rs = "";

        if (objs == null || objs.length == 0)
            return rs;

        for (int i = 0; i < objs.length; i++) {
            rs += objs[i].toString() + splitStr;
        }

        rs = rs.substring(0, rs.length() - 1);

        return rs;
    }

    /**
     * 判断两个String数组是否有交集(相同的元素)
     *
     * @param arr1 源数组1
     * @param arr2 源数组2
     * @return 两个数组第一个相同的元素在arr1的索引位置(第几个元素)
     */
    public static int indexOfSameElement(String[] arr1, String[] arr2) {
        if (arr1 == null) {
            log.error("入参 arr1 为空");
            return -1;
        }
        if (arr2 == null) {
            log.error("入参 arr2 为空");
            return -1;
        } else if (arr1.length == 0 || arr2.length == 0) {
            return -1;
        } else {
            for (int i = 0; i < arr2.length; i++) {
                if (indexOf(arr1, arr2[i]) > -1) {
                    return indexOf(arr1, arr2[i]);
                }
            }
        }
        return -1;
    }

    /**
     * 判断是否为整数
     *
     * @param str 传入的字符串
     * @return 是整数返回true，否则返回false
     */
    public static boolean isInteger(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 判断是否为浮点数，包括double和float
     *
     * @param str 传入的字符串
     * @return 是浮点数返回true，否则返回false
     */
    public static boolean isDouble(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(str).matches();
    }

    /**
     * 获取fullCode的左边指定的层数
     * 1.2.3.4.5.6.7.8.9的形势返回前面几个点号的字符串
     *
     * @param fullCode
     * @param level
     * @return
     */
    public static String getLeftLevels(String fullCode, int level) {
        // 匹配的子串在字符串中的下标
        int index = 0;
        // 计算出现的次数
        int count = 0;
        String findStr = ".";
        while ((index = fullCode.indexOf(findStr, index)) != -1) {
            index += findStr.length();
            count++;
            if (count == level) {
                break;
            }
        }
        if (count == level) {
            return fullCode.substring(0, index);
        }
        return null;
    }

    public static void main(String[] args) {
        String ss = "1.32.33.34.35.36.37.38.74.";
        String s = getLeftLevels(ss, 1);
        System.out.println(s);
        s = getLeftLevels(ss, 2);
        System.out.println(s);
        s = getLeftLevels(ss, 3);
        System.out.println(s);
        s = getLeftLevels(ss, 4);
        System.out.println(s);
        s = getLeftLevels(ss, 5);
        System.out.println(s);
        s = getLeftLevels(ss, 25);
        System.out.println(s);
    }

    //去掉指定分隔符分割的字符串中的重复字符串

    //阿拉伯数字转中文，人民币

    /**
     * 获取两个字符串的相似度
     * 首先看看几个测试结果
     * <p>
     * 字符串1： "亲爱的朋友们，大家早上好。"
     * 字符串2： "亲爱的朋友们，大家晚上好。"
     * <p>
     * 返回结果：92.30769
     * <p>
     * 字符串1： "亲爱的朋友们，大家早上好。"
     * 字符串2： "大家晚上好。"
     * <p>
     * 返回结果：38.461536
     * <p>
     * 字符串1： "大家晚上好，本书作者以娓娓而谈的文笔和行云流水般的故事，写出医药学研究生池大为空怀壮志、无职无权的苦，时来运转、有名有利的难；"
     * 字符串2： "大家晚上好。"
     * <p>
     * 返回结果：7.936507
     * <p>
     * 字符串1： "。好上晚家大"
     * 字符串2： "大家晚上好。"
     * <p>
     * 返回结果：0.0
     * <p>
     * 字符串1： "大大大大大家家家家家晚晚晚晚晚上上上上上好好好好好。。。。。"
     * 字符串2： "大家晚上好。"
     * <p>
     * 返回结果：20.0
     *
     * @param str
     * @param target
     * @return 返回值为float类型。
     */
    public static float getSimilarityRatio(String str, String target) {
        if (str == null || target == null) {
            return 0F;
        }
        int[][] d; // 矩阵
        int n = str.length();
        int m = target.length();
        int i; // 遍历str的
        int j; // 遍历target的
        char ch1; // str的
        char ch2; // target的
        int temp; // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
        if (n == 0 || m == 0) {
            return 0;
        }
        d = new int[n + 1][m + 1];
        // 初始化第一列
        for (i = 0; i <= n; i++) {
            d[i][0] = i;
        }
        // 初始化第一行
        for (j = 0; j <= m; j++) {
            d[0][j] = j;
        }
        // 遍历str
        for (i = 1; i <= n; i++) {
            ch1 = str.charAt(i - 1);
            // 去匹配target
            for (j = 1; j <= m; j++) {
                ch2 = target.charAt(j - 1);
                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
                    temp = 0;
                } else {
                    temp = 1;
                }
                // 左边+1,上边+1, 左上角+temp取最小
                d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + temp);
            }
        }

        return (1 - (float) d[n][m] / Math.max(str.length(), target.length())) * 100F;
    }

}
